package org.fin.session.executor;

import org.fin.config.BoundSql;
import org.fin.exception.NotSupportedException;
import org.fin.pojo.Configuration;
import org.fin.pojo.MappedStatement;
import org.fin.session.statement.ParameterHandler;
import org.fin.session.statement.ResultSetHandler;
import org.fin.utils.GenericTokenParser;
import org.fin.utils.ParameterMapping;
import org.fin.utils.ParameterMappingTokenHandler;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;

public class SimpleExecutor implements Executor {




  /**
   * 基于JDBC执行数据库的操作
   *
   * @param configuration   持久层框核心配置对象
   * @param statement       sql配置对象
   * @param params            sql执行所需的参数
   * @param <R>             执行的sql的返回值类型
   * @return                返回sql执行结果
   */
  @Override
  public <R> List<R> query(Configuration configuration, MappedStatement statement, Object... params) throws SQLException {
    PreparedStatement preparedStatement = getPreparedStatement(configuration, statement, params);

    // 1. 使用JDBC执行sql
    ResultSet resultSet = preparedStatement.executeQuery();

    // 2. 封装返回结果集
    String resultType = statement.getResultType();
    //noinspection unchecked
    return (List<R>) new ResultSetHandler(resultType, resultSet).handle();

  }

  /**
   * 获取PreparedStatement，解析并绑定执行sql语句
   */
  private PreparedStatement getPreparedStatement(Configuration configuration, MappedStatement statement, Object[] params) throws SQLException {
    Objects.requireNonNull(statement, "MappedStatement对象不能为null");
    if (params != null && params.length > 1) {
      throw new NotSupportedException("暂时不支持多参数操作");
    }

    // 1. 注册驱动，获取连接
    Connection connection = configuration.getDataSource().getConnection();

    // 2. 获取sql语句: select * from user where id = #{id} and username = #{username}
    //    转换sql语句: select * from user where id = ? and username = ?
    String sql = statement.getSql();
    BoundSql boundSql = getBoundSql(sql);

    // 3. 获取预处理对象
    PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getParsedSql());


    // 4. 设置参数
    if (params != null && params.length > 0){
      new ParameterHandler(statement.getParamterType(), params[0])
          .handle(boundSql, preparedStatement);
    }
    return preparedStatement;
  }


  @Override
  public void update(Configuration configuration, MappedStatement statement, Object... params) throws SQLException {
    PreparedStatement preparedStatement = getPreparedStatement(configuration, statement, params);
    preparedStatement.executeUpdate();
  }

  @Override
  public void insert(Configuration configuration, MappedStatement statement, Object... params) throws SQLException {
    PreparedStatement preparedStatement = getPreparedStatement(configuration, statement, params);
    preparedStatement.executeUpdate();
  }

  @Override
  public void delete(Configuration configuration, MappedStatement statement, Object... params) throws SQLException {
    PreparedStatement preparedStatement = getPreparedStatement(configuration, statement, params);
    preparedStatement.executeUpdate();
  }


  /**
   * 完成对#{}的解析工作：
   * 1. 将#{}使用?进行代替
   * 2. 解析出#{}里面的值进行存储
   */
  private BoundSql getBoundSql(String sql) {
    // 标记处理类: 配置标记解析器
    ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler();
    GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);

    // 解析完成的sql
    String parsedSql = parser.parse(sql);
    // #{}解析出来的参数名称
    List<ParameterMapping> parameterMappings = handler.getParameterMappings();
    return new BoundSql(parsedSql, parameterMappings);
  }


}
